/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package se.kth.lwr.jeat.core;

import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.measure.quantity.Quantity;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import org.jscience.physics.amount.Amount;
import se.kth.lwr.jeat.samples.onsitetreatment.Units;

/**<pre>
 * The Report is simply a holder of data that express information about some
 * modeling component or results. It is used in Reportable objects which should 
 * return a report that describes the current value(s) of the object. The report
 * is built in form of a list of {@link ReportRecord}s where each record has 
 * four fields:[key, value, unit, comment]. It is allowed to put
 * null objects in any position of the ReportRecord.
 * 
 * The Report uses a single global {@link UnitHandler} with the purpose of 
 * formatting units to prefered ones. As default a DefaultUnitHandler is
 * used. Se {@link DefaultUnitHandler} for details upon the functionallity of
 * the DefaultUnitHandler
 * 
 *
 * @author davidev
 */
public class Report {
    //static unithandler
    private static UnitHandler unitHandler;
    
    //init code for unithandler
    static {
        DefaultUnitHandler defaultHandler = new DefaultUnitHandler();
        defaultHandler.addPreferedUnit(SI.MEGA(SI.JOULE).divide(SI.KILOGRAM));
        //TODO add more default units;
        unitHandler = defaultHandler;
    }
    
    //Keeps the ReportRecords for this report
    private List<ReportRecord> reportRecords=new LinkedList<>();
    
    
    /**
     * Creates an empty Report
     */
    public Report() {
    }
    
    /**
     * Adds a row to the end of the report
     * @param key descriptive key
     */
    public void addRow(Object key){
        reportRecords.add(new ReportRecord(key));
    }
    
    /**Adds a row to the end of the report
     * 
     * @param key descriptive key
     * @param comment key comment
     */
    public void addRow(Object key,Object comment){
        reportRecords.add(new ReportRecord(key,comment));
    }
    
    /**Adds a row to the end of the report. I a prefered unit is compatible
     * with the passad Amount. The Amount will be expressed in this unit.
     * 
     * @param key descriptive key
     * @param amount value
     * @param comment key comment
     */
    
    public void addRow(Object key,Amount<? extends Quantity> amount, Object comment){
        reportRecords.add(new ReportRecord(key,amount,comment));
    }
    
    /**Adds a row to the end of the report and explicitly sets the unit
     * without involving the UnitHandler
     * 
     * @param key descriptive key
     * @param value value
     * @param unit unit
     * @param comment key comment
     */
    
    public void addRow(Object key, Object value, Object unit, Object comment){
        reportRecords.add(new ReportRecord(key, value, unit, comment));
    }
    
    /**Adds a bunch of rows (as a list of {@link ReportRecord) to this Report
     * 
     * @param rows
     */
    public void addRows(List<ReportRecord> rows){
        reportRecords.addAll(rows);
    }
    
    
    
    /**Set a custom unitHandler that handle possible unit formatting for all 
     * Report objects. By default the {@link DefaultUnitHandler} is used.
     * 
     * @param unitHandler a custom UnitHandler
     */
    public static void setUnitHandler(UnitHandler unitHandler) {
        Report.unitHandler = unitHandler;
    }
    
    /**
     * 
     * @return the full set of ReportRecords in this Report as an unmodifiable
     * list
     */

    public List<ReportRecord> getReportRecords() {
        return Collections.unmodifiableList(reportRecords);
    }
    
    
    
    /**
     * 
     * 
     * @return the currently used UnitHanlder
     */

    public static UnitHandler getUnitHandler() {
        return unitHandler;
    }
    
    /**
     * A wrapper class for the four fields: key, value, unit, comment. It uses
     * the current UnitHandler to format incoming Amounts.
     * 
     */
    public class ReportRecord {

        private Object key;
        private Object value;
        private Object comment;
        private Object unit;

        public ReportRecord(Object key) {
            this(key, null, null,null);
        }

        public ReportRecord(Object key, Object comment) {
            this(key, null,null, comment);
        }
        
        public ReportRecord(Object key, Object value, Object unit, Object comment){
            this.key = key;
            this.value = value;
            this.unit=unit;
            this.comment=comment;
            
        }
//TODO format numbers (decimals)
        public ReportRecord(Object key, Amount<? extends Quantity> value, Object comment) {
            //Default value if null passed
            Amount<? extends Quantity> inPrefUnit=Amount.ZERO;
            if(value!=null){
                inPrefUnit=unitHandler.toPreferedUnit(value);
            }
            this.key = key;
            this.value = inPrefUnit.getEstimatedValue();
            this.unit=inPrefUnit.getUnit();
            this.comment=comment;

        }

        public Object getKey() {
            return key;
        }

        public Object getUnit() {
            return unit;
        }

        public Object getValue() {
            return value;
        }

        public Object getComment() {
            return comment;
        }
    }
}
